package ink.xiaobaibai.rbac;

import com.alibaba.fastjson.JSON;
import ink.xiaobaibai.response.ResponseFormat;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

/**
 * @description: rbac集合过滤器
 * @author: 小白白
 * @create: 2021-05-15
 **/

/**
 * 不要注入IOC,否则会经过两次过滤器
 */
public class RbacSecurityFilter2 extends OncePerRequestFilter {

    private FilterInvocationSecurityMetadataSourceImpl securityMetadataSource;

    private AccessDecisionManagerImpl accessDecisionManager;

    public RbacSecurityFilter2(FilterInvocationSecurityMetadataSourceImpl securityMetadataSource,
                               AccessDecisionManagerImpl accessDecisionManager) {
        this.securityMetadataSource = securityMetadataSource;
        this.accessDecisionManager = accessDecisionManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (this.beforeInvocation(request)) {
            filterChain.doFilter(request, response);
        } else {
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(JSON.toJSONString(ResponseFormat.fail("权限不足")));
        }
    }

    private boolean beforeInvocation(HttpServletRequest request) {
        Collection<ConfigAttribute> attributes = this.securityMetadataSource.getAttributes(request);
        Authentication authenticated = this.authenticateIfRequired();
        try {
            this.accessDecisionManager.decide(authenticated, request, attributes);
        } catch (AccessDeniedException e) {
            return false;
        }
        return true;
    }

    private Authentication authenticateIfRequired() {
        //当前filter在最后面
        return SecurityContextHolder.getContext().getAuthentication();
    }

}
